x86: enable directed EOI
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 23 Nov 2009 06:58:19 +0000 (06:58 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 23 Nov 2009 06:58:19 +0000 (06:58 +0000)
This patch enables directed EOI on latest processor. With this, the
broadcast of EOI would be suppressed upon LAPIC EOI, so VMM is
required to perform a directed EOI to the IOxAPIC generating the
interrupt by writting to its EOI register.(Pls. refer SDM 3A 10.5.5)

This is useful for ioapic_ack_old to avoid the spurious interrupt
storm, which is the reason why ioapic_ack_new is used.

Signed-Off-By: Zhai Edwin <edwin.zhai@intel.com>
xen/arch/x86/apic.c
xen/arch/x86/io_apic.c
xen/include/asm-x86/apic.h
xen/include/asm-x86/apicdef.h
xen/include/asm-x86/io_apic.h

index 64be332ca6ceb0fafabac3dc6c359cfe5be2aff5..4c4a3de0d484876db3a068256c471fab71a1eaa7 100644 (file)
@@ -68,6 +68,7 @@ static int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enabl
 int apic_verbosity;
 
 int x2apic_enabled __read_mostly = 0;
+int directed_eoi_enabled __read_mostly = 0;
 
 /*
  * The following vectors are part of the Linux architecture, there
@@ -348,6 +349,7 @@ void disable_local_APIC(void)
     }
 }
 
+extern int ioapic_ack_new;
 /*
  * This is to verify that we're looking at a real local APIC.
  * Check these against your board if the CPUs aren't getting
@@ -387,6 +389,18 @@ int __init verify_local_APIC(void)
     if (reg1 < 0x02 || reg1 == 0xff)
         return 0;
 
+    /*
+     * Detecting directed EOI on BSP:
+     * If having directed EOI support in lapic, force to use ioapic_ack_old,
+     * and enable the directed EOI for intr handling.
+     */
+    if ( reg0 & APIC_LVR_DIRECTED_EOI )
+    {
+        ioapic_ack_new = 0;
+        directed_eoi_enabled = 1;
+        printk("Enabled directed EOI with ioapic_ack_old on!\n");
+    }
+
     /*
      * The ID register is read/write in a real APIC.
      */
@@ -575,6 +589,17 @@ void __devinit setup_local_APIC(void)
      * Set spurious IRQ vector
      */
     value |= SPURIOUS_APIC_VECTOR;
+
+    /*
+     * Enable directed EOI
+     */
+    if ( directed_eoi_enabled )
+    {
+        value |= APIC_SPIV_DIRECTED_EOI;
+        apic_printk(APIC_VERBOSE, "Suppress EOI broadcast on CPU#%d\n",
+                    smp_processor_id());
+    }
+
     apic_write_around(APIC_SPIV, value);
 
     /*
index 9422fb494382617351692c40f6f16baeb7e77120..95a0a60938efe56635280be94a37f4ed728bfb95 100644 (file)
@@ -197,6 +197,30 @@ static void unmask_IO_APIC_irq (unsigned int irq)
     spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
+static void __eoi_IO_APIC_irq(unsigned int irq)
+{
+    struct irq_pin_list *entry = irq_2_pin + irq;
+    unsigned int pin, vector = IO_APIC_VECTOR(irq);
+
+    for (;;) {
+        pin = entry->pin;
+        if (pin == -1)
+            break;
+        io_apic_eoi(entry->apic, vector);
+        if (!entry->next)
+            break;
+        entry = irq_2_pin + entry->next;
+    }
+}
+
+static void eoi_IO_APIC_irq(unsigned int irq)
+{
+    unsigned long flags;
+    spin_lock_irqsave(&ioapic_lock, flags);
+    __eoi_IO_APIC_irq(irq);
+    spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
 static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
 {
     struct IO_APIC_route_entry entry;
@@ -1464,7 +1488,8 @@ static void mask_and_ack_level_ioapic_irq (unsigned int irq)
     if ( ioapic_ack_new )
         return;
 
-    mask_IO_APIC_irq(irq);
+    if ( !directed_eoi_enabled )
+        mask_IO_APIC_irq(irq);
 
 /*
  * It appears there is an erratum which affects at least version 0x11
@@ -1511,8 +1536,14 @@ static void end_level_ioapic_irq (unsigned int irq)
 
     if ( !ioapic_ack_new )
     {
-        if ( !(irq_desc[irq].status & IRQ_DISABLED) )
+        if ( irq_desc[irq].status & IRQ_DISABLED )
+            return;
+
+        if ( directed_eoi_enabled )
+            eoi_IO_APIC_irq(irq);
+        else
             unmask_IO_APIC_irq(irq);
+
         return;
     }
 
index 99826c7b27e0697b5afcbfac5f987062210fc19d..4bf4c70d43096e1adeb8696baaad22b4385583b7 100644 (file)
@@ -23,6 +23,7 @@
 
 extern int apic_verbosity;
 extern int x2apic_enabled;
+extern int directed_eoi_enabled;
 
 extern void enable_x2apic(void);
 
index 87a65997f042497c3b63fc81378c5ea9ffcc648b..4a026b13434ebc1c1679fd16b6b6f2de99dd1da6 100644 (file)
@@ -16,6 +16,7 @@
 #define                        SET_xAPIC_ID(x)         (((x)<<24))
 #define                APIC_LVR        0x30
 #define                        APIC_LVR_MASK           0xFF00FF
+#define                        APIC_LVR_DIRECTED_EOI   (1 << 24)
 #define                        GET_APIC_VERSION(x)     ((x)&0xFF)
 #define                        GET_APIC_MAXLVT(x)      (((x)>>16)&0xFF)
 #define                        APIC_INTEGRATED(x)      ((x)&0xF0)
@@ -39,6 +40,7 @@
 #define                APIC_SPIV       0xF0
 #define                        APIC_SPIV_FOCUS_DISABLED        (1<<9)
 #define                        APIC_SPIV_APIC_ENABLED          (1<<8)
+#define                        APIC_SPIV_DIRECTED_EOI          (1<<12)
 #define                APIC_ISR        0x100
 #define         APIC_ISR_NR     0x8     /* Number of 32 bit ISR registers. */
 #define                APIC_TMR        0x180
index 6781ac1bac0141ac4867ddccfac55dc37ea53989..e47ee0c1685289d1215be5ada1c75d67178346ad 100644 (file)
@@ -147,6 +147,11 @@ static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned i
        *(IO_APIC_BASE(apic)+4) = value;
 }
 
+static inline void io_apic_eoi(unsigned int apic, unsigned int vector)
+{
+       *(IO_APIC_BASE(apic)+16) = vector;
+}
+
 /*
  * Re-write a value: to be used for read-modify-write
  * cycles where the read already set up the index register.